/**
 * 这是浏览器与WPS通信的SDK，是WPS提供的SDK
 * 无需修改
 * 直接引用到业务系统前端调用即可
 * 可覆盖如下使用场景：
 *  1. 通过浏览器中的页面直接启动WPS
 *  2. 浏览器与WPS双向通信，WPS发消息，浏览器前端页面可接受并解析
 */

(function(global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? (module.exports = factory(global)) : typeof define === 'function' && define.amd ? define(factory) : factory(global);
})(typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this, function(global) {
  global = global || {};
  var bFinished = true;

  function getHttpObj() {
    var httpobj = null;
    if (IEVersion() < 10) {
      try {
        httpobj = new XDomainRequest();
      } catch (e1) {
        httpobj = new createXHR();
      }
    } else {
      httpobj = new createXHR();
    }
    return httpobj;
  }
  //兼容IE低版本的创建xmlhttprequest对象的方法
  function createXHR() {
    if (typeof XMLHttpRequest != 'undefined') {
      //兼容高版本浏览器
      return new XMLHttpRequest();
    } else if (typeof ActiveXObject != 'undefined') {
      //IE6 采用 ActiveXObject， 兼容IE6
      var versions = [
        //由于MSXML库有3个版本，因此都要考虑
        'MSXML2.XMLHttp.6.0',
        'MSXML2.XMLHttp.3.0',
        'MSXML2.XMLHttp',
      ];

      for (var i = 0; i < versions.length; i++) {
        try {
          return new ActiveXObject(versions[i]);
        } catch (e) {
          //跳过
        }
      }
    } else {
      throw new Error('您的浏览器不支持XHR对象');
    }
  }

  function startWps(options) {
    if (!bFinished && !options.concurrent) {
      if (options.callback)
        options.callback({
          status: 1,
          message: '上一次请求没有完成',
        });
      return;
    }
    bFinished = false;

    function startWpsInnder(tryCount) {
      if (tryCount <= 0) {
        if (bFinished) return;
        bFinished = true;
        if (options.callback)
          options.callback({
            status: 2,
            message: '请允许浏览器打开WPS Office',
          });
        return;
      }
      var xmlReq = getHttpObj();
      //WPS客户端提供的接收参数的本地服务，HTTP服务端口为58890，HTTPS服务端口为58891
      //这俩配置，取一即可，不可同时启用
      xmlReq.open('POST', options.url);
      xmlReq.onload = function(res) {
        bFinished = true;
        if (options.callback) {
        }
        options.callback({
          status: 0,
          response: IEVersion() < 10 ? xmlReq.responseText : res.target.response,
        });
      };
      xmlReq.ontimeout = xmlReq.onerror = function(res) {
        xmlReq.bTimeout = true;
        if (tryCount == options.tryCount && options.bPop) {
          //打开wps并传参
          window.location.href = 'ksoWPSCloudSvr://start=RelayHttpServer'; //是否启动wps弹框
        }
        setTimeout(function() {
          startWpsInnder(tryCount - 1);
        }, 1000);
      };
      if (IEVersion() < 10) {
        xmlReq.onreadystatechange = function() {
          if (xmlReq.readyState != 4) return;
          if (xmlReq.bTimeout) {
            return;
          }
          if (xmlReq.status === 200) xmlReq.onload();
          else xmlReq.onerror();
        };
      }
      xmlReq.timeout = options.timeout;
      xmlReq.send(options.sendData);
    }
    startWpsInnder(options.tryCount);
    return;
  }

  var fromCharCode = String.fromCharCode;
  // encoder stuff
  var cb_utob = function(c) {
    if (c.length < 2) {
      var cc = c.charCodeAt(0);
      return cc < 0x80 ? c : cc < 0x800 ? fromCharCode(0xc0 | (cc >>> 6)) + fromCharCode(0x80 | (cc & 0x3f)) : fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + fromCharCode(0x80 | (cc & 0x3f));
    } else {
      var cc = 0x10000 + (c.charCodeAt(0) - 0xd800) * 0x400 + (c.charCodeAt(1) - 0xdc00);
      return fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + fromCharCode(0x80 | (cc & 0x3f));
    }
  };
  var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
  var utob = function(u) {
    return u.replace(re_utob, cb_utob);
  };
  var _encode = function(u) {
    var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]';
    if (isUint8Array) return u.toString('base64');
    else return btoa(utob(String(u)));
  };

  if (typeof global.btoa !== 'function') global.btoa = func_btoa;

  function func_btoa(input) {
    var str = String(input);
    var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    for (
      // initialize result and counter
      var block, charCode, idx = 0, map = chars, output = '';
      // if the next str index does not exist:
      //   change the mapping table to "="
      //   check if d has no fractional digits
      str.charAt(idx | 0) || ((map = '='), idx % 1);
      // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
      output += map.charAt(63 & (block >> (8 - (idx % 1) * 8)))
    ) {
      charCode = str.charCodeAt((idx += 3 / 4));
      if (charCode > 0xff) {
        throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
      }
      block = (block << 8) | charCode;
    }
    return output;
  }

  var encode = function(u, urisafe) {
    return !urisafe
      ? _encode(u)
      : _encode(String(u))
          .replace(/[+\/]/g, function(m0) {
            return m0 == '+' ? '-' : '_';
          })
          .replace(/=/g, '');
  };

  function IEVersion() {
    var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
    var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; //判断是否IE<11浏览器
    var isEdge = userAgent.indexOf('Edge') > -1 && !isIE; //判断是否IE的Edge浏览器
    var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
    if (isIE) {
      var reIE = new RegExp('MSIE (\\d+\\.\\d+);');
      reIE.test(userAgent);
      var fIEVersion = parseFloat(RegExp['$1']);
      if (fIEVersion == 7) {
        return 7;
      } else if (fIEVersion == 8) {
        return 8;
      } else if (fIEVersion == 9) {
        return 9;
      } else if (fIEVersion == 10) {
        return 10;
      } else {
        return 6; //IE版本<=7
      }
    } else if (isEdge) {
      return 20; //edge
    } else if (isIE11) {
      return 11; //IE11
    } else {
      return 30; //不是ie浏览器
    }
  }

  function WpsStart(clientType, name, func, param, useHttps, callback, tryCount, bPop) {
    var startInfo = {
      name: name,
      function: func,
      info: param,
    };
    var strData = JSON.stringify(startInfo);
    if (IEVersion() < 10) {
      try {
        eval("strData = '" + JSON.stringify(startInfo) + "';");
      } catch (err) {}
    }

    var baseData = encode(strData);
    var url = 'http://10.13.76.111:58890/' + clientType + '/runParams';
    if (useHttps) url = 'https://10.13.76.111:58891/' + clientType + '/runParams';
    var data = 'ksowebstartup' + clientType + '://' + baseData;
    startWps({
      url: url,
      sendData: data,
      callback: callback,
      tryCount: tryCount,
      bPop: bPop,
      timeout: 5000,
      concurrent: false,
    });
  }

  function WpsStartWrap(clientType, name, func, param, callback) {
    WpsStart(clientType, name, func, param, false, callback, 4, true);
  }

  function WpsStartWrapHttps(clientType, name, func, param, callback) {
    WpsStart(clientType, name, func, param, true, callback, 4, true);
  }

  var exId = 0;
  /**
   * 支持浏览器触发，WPS有返回值的启动
   *
   * @param {*} clientType	组件类型
   * @param {*} name			WPS加载项名称
   * @param {*} func			WPS加载项入口方法
   * @param {*} param			参数：包括WPS加载项内部定义的方法，参数等
   * @param {*} useHttps		是否使用https协议
   * @param {*} callback		回调函数
   * @param {*} tryCount		重试次数
   * @param {*} bPop			是否弹出浏览器提示对话框
   */
  function WpsStartWrapExInner(clientType, name, func, param, useHttps, callback, tryCount, bPop) {
    var rspUrl = 'http://10.13.76.111:58890/transferEcho/runParams';
    if (useHttps) rspUrl = 'https://10.13.76.111:58891/transferEcho/runParams';
    var time = new Date();
    var cmdId = 'js' + time.getTime() + '_' + exId;
    var infocontent = JSON.stringify(param);
    var funcEx = 'var res = ' + func;
    var cbCode = "var xhr = new XMLHttpRequest();xhr.open('POST', '" + rspUrl + "');xhr.send(JSON.stringify({id: '" + cmdId + "', response: res}));"; //res 为func执行返回值
    var infoEx = infocontent + ');' + cbCode + 'void(0';
    //固定格式，无需修改
    var startInfo = {
      name: name,
      function: funcEx,
      info: infoEx,
    };
    var strData = JSON.stringify(startInfo);
    if (IEVersion() < 10) {
      try {
        eval("strData = '" + JSON.stringify(startInfo) + "';");
      } catch (err) {}
    }

    var baseData = encode(strData);
    var url = 'http://10.13.76.111:58890/transfer/runParams';
    if (useHttps) url = 'https://10.13.76.111:58891/transfer/runParams';
    var data = 'ksowebstartup' + clientType + '://' + baseData;
    var wrapper = {
      id: cmdId,
      app: clientType,
      data: data,
    };
    wrapper = JSON.stringify(wrapper);
    startWps({
      url: url,
      sendData: wrapper,
      callback: callback,
      tryCount: tryCount,
      bPop: bPop,
      timeout: 0,
      concurrent: true,
    });
  }

  var serverVersion = 'wait';

  function WpsStartWrapVersionInner(clientType, name, func, param, useHttps, callback) {
    if (serverVersion == 'wait') {
      var url = 'http://10.13.76.111:58890/version';
      if (useHttps) url = 'https://10.13.76.111:58891/version';
      startWps({
        url: url,
        data: '',
        callback: function(res) {
          if (res.status !== 0) {
            callback(res);
            return;
          }
          serverVersion = res.response;
          if (serverVersion === '') {
            WpsStart(clientType, name, func, param, useHttps, callback, 1, false);
          } else {
            WpsStartWrapExInner(clientType, name, func, param, useHttps, callback, 1, false);
          }
        },
        tryCount: 4,
        bPop: true,
        timeout: 5000,
      });
    } else {
      if (serverVersion === '') {
        WpsStartWrap(clientType, name, func, param, useHttps, callback);
      } else {
        WpsStartWrapExInner(clientType, name, func, param, useHttps, callback, 1, true);
      }
    }
  }

  var RegWebNotifyID = null;
  /**
   * 注册一个前端页面接收WPS传来消息的方法
   * @param {*} clientType wps | et | wpp
   * @param {*} name WPS加载项的名称
   * @param {*} callback 回调函数
   */
  function RegWebNotify(clientType, name, callback) {
    if (RegWebNotifyID) {
      return;
    }

    RegWebNotifyID = new Date().valueOf() + '';
    var paramStr = {
      id: RegWebNotifyID,
      name: name,
      type: clientType,
    };
    var askItem = function() {
      var xhr = WpsInvoke.CreateXHR();
      xhr.onload = function(e) {
        callback(xhr.responseText);
        window.setTimeout(askItem, 300);
      };
      xhr.onerror = function(e) {
        window.setTimeout(askItem, 10000);
      };
      xhr.ontimeout = function(e) {
        window.setTimeout(askItem, 10000);
      };
      if (IEVersion() < 10) {
        xhr.onreadystatechange = function() {
          if (xhr.readyState != 4) return;
          if (xhr.bTimeout) {
            return;
          }
          if (xhr.status === 200) xhr.onload();
          else xhr.onerror();
        };
      }
      xhr.open('POST', 'http://10.13.76.111:58890/askwebnotify', true);
      xhr.send(JSON.stringify(paramStr));
    };

    window.setTimeout(askItem, 2000);
  }

  function WpsStartWrapVersion(clientType, name, func, param, callback) {
    WpsStartWrapVersionInner(clientType, name, func, param, false, callback);
  }

  function WpsStartWrapHttpsVersion(clientType, name, func, param, callback) {
    WpsStartWrapVersionInner(clientType, name, func, param, true, callback);
  }

  global.WpsInvoke = {
    InvokeAsHttp: WpsStartWrapVersion,
    InvokeAsHttps: WpsStartWrapHttpsVersion,
    RegWebNotify: RegWebNotify,
    ClientType: {
      wps: 'wps',
      et: 'et',
      wpp: 'wpp',
    },
    CreateXHR: createXHR,
  };

  return {
    WpsInvoke: global.WpsInvoke,
  };
});
